<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>利用Object 的set 和get 属性做数据响应式</title>
  <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
  <style>
    body {
      width: 100%;
      height: 100%;
    }

    .box {
      width: 500px;
      height: 100px;
      overflow-y: scroll;


    }

    .red {
      width: 60%;
      height: 400px;

      background: red;
    }
  </style>
</head>

<body id="a">
  <div class="box" id="box">
    <div class="red" id="red">
    </div>
    111111
  </div>
  <!-- js 数组下标可以为负数，但是负索引不增加length
    await 后面跟一个promsie 对象，记住一定要使用回调函数resolve或者reject, 只要promsie 状态为pending,就会一直卡住不懂 
    -->

</body>


<script>
  //目标， 使用async  将将并发数始终控制在5个左右，总共需要抓取的连接数在200个

  let total = 200
  let maxLimits = 5

  // 伪造的随机时间函数
  const timeRandom = function () {
    let min = 1;
    let max = 10;
    let range = max - min;
    return (1 + range * Math.random()) * 1000;
  }

  // function fetchUrl(url) {
  //   let delay = timeRandom()
  //   let startTime = new Date().getTime();

  //   return new Promise(function (resolve) {
  //     const timerId = setTimeout(() => {
  //       let time = (new Date().getTime() - startTime) / 1000;
  //       let estimatedTime = delay / 1000;
  //       console.log('当前任务' + url + '已经完成', '该任务耗时' + time + 's', '预估时间' + estimatedTime + 's');
  //       clearTimeout(timerId);
  //       // 异步结果
  //       let data = '当前任务' + url +'的结果';
  //       resolve(data);

  //     }, delay)
  //   })
  // }
   function asyncF(url) {
    let delay = timeRandom()
    let startTime = new Date().getTime();

    return new Promise(function (resolve) {
      const timerId = setTimeout(() => {
        let time = (new Date().getTime() - startTime) / 1000;
        let estimatedTime = delay / 1000;
        console.log('当前任务' + url + '已经完成', '该任务耗时' + time + 's', '预估时间' + estimatedTime + 's');
        clearTimeout(timerId);
        // 异步结果
        let data = '当前任务' + url +'的结果';
        resolve(data);

      }, delay)
    })
  }

  // 伪造的需要总共抓取的url 数组 --- 外部输入数据
  let arrTasks = Array(6).fill(1).map((v, i) => i);

  // 解耦，参数提取，外界传入条件
  async function asyncMapLimit(urls = [], mapLimit = 3, fn, asyncFn = function (url, data, fn) { }) {
    // 异步操作
    function fetchUrl(url) {
      return fn(url)
    }
    // 将前五个位置一次性进行,也要单独清理
    let arrTaskLimits = urls.slice(0, mapLimit);
    let finalResult = [];
    // 副作用
    function step(url) {
      let currentEmptyIndex = arrTaskLimits.findIndex(url => url == url);
      arrTaskLimits[currentEmptyIndex] = null;
    }

    // 建立指定数量的位置
    arrTaskLimits.forEach(url => {
      fetchUrl(url).then((data) => {
        step(url);
        asyncFn(url, data);
      })
    });

    // 空包执行技巧，发送一个空执行，让await 等待后爱上，让连接数始终保持在5个，不使用setInterval
    function emptyThread() {
      return new Promise(function (resolve) {
        const timer = setTimeout(() => {
          console.log('暂停一秒,空任务');
          clearTimeout(timer);
          resolve();
        }, 1000);
      })
    }
    // 5个位置，一个位置出来了就往这个位置差值
    for (let i = mapLimit; i < urls.length; i++) {
      // 遍历arrTaskLimits， 如果有空位置直接添加，没有空位置要暂停等待
      let hasEmptyIndex = arrTaskLimits.findIndex(v => v === null);
      // 没有空位，这里的问题在于我还是没没有控制并发的次数
      // 比如头五个都是超长的时间，后面每一个都是-1.那我等于新开好多个连接，还是会被封
      if (hasEmptyIndex == -1) {
        await emptyThread();
        i--;
      } else {
        arrTaskLimits[hasEmptyIndex] = urls[i];
        fetchUrl(urls[i]).then((data) => {
          step(urls[i]);
          asyncFn(urls[i], data);
        });
      }

    }



  }
  // 第三个参数是一个函数，函数第一项为arrTask 的每一项，第二项为每一项的最终处理结果
  asyncMapLimit(arrTasks, 5, asyncF ,function(task,data){
    console.log('当前任务'+task ,'任务数据:'+ data)
  })


</script>

</html>